// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.inventory;

import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import zombie.characters.IsoGameCharacter;
import zombie.inventory.types.InventoryContainer;

public final class CompressIdenticalItems {
    private static final int BLOCK_SIZE = 1024;
    private static final ThreadLocal<CompressIdenticalItems.PerThreadData> perThreadVars = new ThreadLocal<CompressIdenticalItems.PerThreadData>() {
        protected CompressIdenticalItems.PerThreadData initialValue() {
            return new CompressIdenticalItems.PerThreadData();
        }
    };

    private static int bufferSize(int _int) {
        return (_int + 1024 - 1) / 1024 * 1024;
    }

    private static ByteBuffer ensureCapacity(ByteBuffer byteBuffer, int _int) {
        if (byteBuffer == null || byteBuffer.capacity() < _int) {
            byteBuffer = ByteBuffer.allocate(bufferSize(_int));
        }

        return byteBuffer;
    }

    private static ByteBuffer ensureCapacity(ByteBuffer byteBuffer0) {
        if (byteBuffer0 == null) {
            return ByteBuffer.allocate(1024);
        } else if (byteBuffer0.capacity() - byteBuffer0.position() < 1024) {
            ByteBuffer byteBuffer1 = ensureCapacity(null, byteBuffer0.position() + 1024);
            return byteBuffer1.put(byteBuffer0.array(), 0, byteBuffer0.position());
        } else {
            ByteBuffer byteBuffer2 = ensureCapacity(null, byteBuffer0.capacity() + 1024);
            return byteBuffer2.put(byteBuffer0.array(), 0, byteBuffer0.position());
        }
    }

    private static boolean setCompareItem(CompressIdenticalItems.PerThreadData perThreadData, InventoryItem inventoryItem) throws IOException {
        ByteBuffer byteBuffer = perThreadData.itemCompareBuffer;
        byteBuffer.clear();
        int int0 = inventoryItem.id;
        inventoryItem.id = 0;

        try {
            while (true) {
                try {
                    byteBuffer.putInt(0);
                    inventoryItem.save(byteBuffer, false);
                    int int1 = byteBuffer.position();
                    byteBuffer.position(0);
                    byteBuffer.putInt(int1);
                    byteBuffer.position(int1);
                    return true;
                } catch (BufferOverflowException bufferOverflowException) {
                    byteBuffer = ensureCapacity(byteBuffer);
                    byteBuffer.clear();
                    perThreadData.itemCompareBuffer = byteBuffer;
                }
            }
        } finally {
            inventoryItem.id = int0;
        }
    }

    private static boolean areItemsIdentical(CompressIdenticalItems.PerThreadData perThreadData, InventoryItem inventoryItem0, InventoryItem inventoryItem1) throws IOException {
        if (inventoryItem0 instanceof InventoryContainer) {
            ItemContainer itemContainer0 = ((InventoryContainer)inventoryItem0).getInventory();
            ItemContainer itemContainer1 = ((InventoryContainer)inventoryItem1).getInventory();
            if (!itemContainer0.getItems().isEmpty() || !itemContainer1.getItems().isEmpty()) {
                return false;
            }
        }

        ByteBuffer byteBuffer0 = inventoryItem0.getByteData();
        ByteBuffer byteBuffer1 = inventoryItem1.getByteData();
        if (byteBuffer0 != null) {
            assert byteBuffer0.position() == 0;

            if (!byteBuffer0.equals(byteBuffer1)) {
                return false;
            }
        } else if (byteBuffer1 != null) {
            return false;
        }

        ByteBuffer byteBuffer2 = null;
        int int0 = inventoryItem1.id;
        inventoryItem1.id = 0;

        while (true) {
            try {
                byteBuffer2 = perThreadData.itemCompareBuffer;
                byteBuffer2.position(0);
                int int1 = byteBuffer2.getInt();
                int int2 = byteBuffer2.position();
                byteBuffer2.position(int1);
                int int3 = byteBuffer2.position();
                inventoryItem1.save(byteBuffer2, false);
                int int4 = byteBuffer2.position();
                if (int4 - int3 != int1 - int2) {
                    return false;
                }

                for (int int5 = 0; int5 < int1 - int2; int5++) {
                    if (byteBuffer2.get(int2 + int5) != byteBuffer2.get(int3 + int5)) {
                        return false;
                    }
                }

                return true;
            } catch (BufferOverflowException bufferOverflowException) {
                byteBuffer2 = ensureCapacity(byteBuffer2);
                byteBuffer2.clear();
                perThreadData.itemCompareBuffer = byteBuffer2;
                setCompareItem(perThreadData, inventoryItem0);
            } finally {
                inventoryItem1.id = int0;
            }
        }
    }

    public static ArrayList<InventoryItem> save(ByteBuffer output, ArrayList<InventoryItem> items, IsoGameCharacter noCompress) throws IOException {
        CompressIdenticalItems.PerThreadData perThreadData = (CompressIdenticalItems.PerThreadData)perThreadVars.get();
        CompressIdenticalItems.PerCallData perCallData = perThreadData.allocSaveVars();
        HashMap hashMap = perCallData.typeToItems;
        ArrayList arrayList0 = perCallData.types;

        try {
            for (int int0 = 0; int0 < items.size(); int0++) {
                String string = ((InventoryItem)items.get(int0)).getFullType();
                if (!hashMap.containsKey(string)) {
                    hashMap.put(string, perCallData.allocItemList());
                    arrayList0.add(string);
                }

                ((ArrayList)hashMap.get(string)).add((InventoryItem)items.get(int0));
            }

            int int1 = output.position();
            output.putShort((short)0);
            int int2 = 0;

            for (int int3 = 0; int3 < arrayList0.size(); int3++) {
                ArrayList arrayList1 = (ArrayList)hashMap.get(arrayList0.get(int3));

                for (int int4 = 0; int4 < arrayList1.size(); int4++) {
                    InventoryItem inventoryItem = (InventoryItem)arrayList1.get(int4);
                    perCallData.savedItems.add(inventoryItem);
                    int int5 = 1;
                    int int6 = int4 + 1;
                    if (noCompress == null || !noCompress.isEquipped(inventoryItem)) {
                        setCompareItem(perThreadData, inventoryItem);

                        while (int4 + 1 < arrayList1.size() && areItemsIdentical(perThreadData, inventoryItem, (InventoryItem)arrayList1.get(int4 + 1))) {
                            perCallData.savedItems.add((InventoryItem)arrayList1.get(int4 + 1));
                            int4++;
                            int5++;
                        }
                    }

                    output.putInt(int5);
                    inventoryItem.saveWithSize(output, false);
                    if (int5 > 1) {
                        for (int int7 = int6; int7 <= int4; int7++) {
                            output.putInt(((InventoryItem)arrayList1.get(int7)).id);
                        }
                    }

                    int2++;
                }
            }

            int int8 = output.position();
            output.position(int1);
            output.putShort((short)int2);
            output.position(int8);
        } finally {
            perCallData.next = perThreadData.saveVars;
            perThreadData.saveVars = perCallData;
        }

        return perCallData.savedItems;
    }

    public static ArrayList<InventoryItem> load(
        ByteBuffer input, int WorldVersion, ArrayList<InventoryItem> Items, ArrayList<InventoryItem> IncludingObsoleteItems
    ) throws IOException {
        CompressIdenticalItems.PerThreadData perThreadData = (CompressIdenticalItems.PerThreadData)perThreadVars.get();
        CompressIdenticalItems.PerCallData perCallData = perThreadData.allocSaveVars();
        if (Items != null) {
            Items.clear();
        }

        if (IncludingObsoleteItems != null) {
            IncludingObsoleteItems.clear();
        }

        try {
            short _short = input.getShort();

            for (int int0 = 0; int0 < _short; int0++) {
                int int1 = 1;
                if (WorldVersion >= 149) {
                    int1 = input.getInt();
                } else if (WorldVersion >= 128) {
                    int1 = input.getShort();
                }

                int int2 = input.position();
                InventoryItem inventoryItem = InventoryItem.loadItem(input, WorldVersion);
                if (inventoryItem == null) {
                    int int3 = int1 > 1 ? (int1 - 1) * 4 : 0;
                    input.position(input.position() + int3);

                    for (int int4 = 0; int4 < int1; int4++) {
                        if (IncludingObsoleteItems != null) {
                            IncludingObsoleteItems.add(null);
                        }

                        perCallData.savedItems.add(null);
                    }
                } else {
                    for (int int5 = 0; int5 < int1; int5++) {
                        if (int5 > 0) {
                            input.position(int2);
                            inventoryItem = InventoryItem.loadItem(input, WorldVersion);
                        }

                        if (Items != null) {
                            Items.add(inventoryItem);
                        }

                        if (IncludingObsoleteItems != null) {
                            IncludingObsoleteItems.add(inventoryItem);
                        }

                        perCallData.savedItems.add(inventoryItem);
                    }

                    if (WorldVersion >= 128) {
                        for (int int6 = 1; int6 < int1; int6++) {
                            int int7 = input.getInt();
                            inventoryItem = (InventoryItem)perCallData.savedItems.get(perCallData.savedItems.size() - int1 + int6);
                            if (inventoryItem != null) {
                                inventoryItem.id = int7;
                            }
                        }
                    }
                }
            }
        } finally {
            perCallData.next = perThreadData.saveVars;
            perThreadData.saveVars = perCallData;
        }

        return perCallData.savedItems;
    }

    public static void save(ByteBuffer output, InventoryItem item) throws IOException {
        output.putShort((short)1);
        output.putInt(1);
        item.saveWithSize(output, false);
    }

    private static class PerCallData {
        final ArrayList<String> types = new ArrayList();
        final HashMap<String, ArrayList<InventoryItem>> typeToItems = new HashMap();
        final ArrayDeque<ArrayList<InventoryItem>> itemLists = new ArrayDeque();
        final ArrayList<InventoryItem> savedItems = new ArrayList();
        CompressIdenticalItems.PerCallData next;

        void reset() {
            for (int _int = 0; _int < this.types.size(); _int++) {
                ArrayList arrayList = (ArrayList)this.typeToItems.get(this.types.get(_int));
                arrayList.clear();
                this.itemLists.push(arrayList);
            }

            this.types.clear();
            this.typeToItems.clear();
            this.savedItems.clear();
        }

        ArrayList<InventoryItem> allocItemList() {
            return this.itemLists.isEmpty() ? new ArrayList() : (ArrayList)this.itemLists.pop();
        }
    }

    private static class PerThreadData {
        CompressIdenticalItems.PerCallData saveVars;
        ByteBuffer itemCompareBuffer = ByteBuffer.allocate(1024);

        CompressIdenticalItems.PerCallData allocSaveVars() {
            if (this.saveVars == null) {
                return new CompressIdenticalItems.PerCallData();
            } else {
                CompressIdenticalItems.PerCallData perCallData = this.saveVars;
                perCallData.reset();
                this.saveVars = this.saveVars.next;
                return perCallData;
            }
        }
    }
}
